package santiago.domain;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import static santiago.domain.DifficultyLevel.Easy;

public class Gameboard implements Serializable {

    private int Spring;
    private List<Plantation> Plantations;
    private Node[] Nodes;
    private GameParameters InitializationParameters;

    public Gameboard(GameParameters InitializationParameters) {
        this(InitializationParameters.getLevel(), InitializationParameters.hasPalmTree());
        this.InitializationParameters = InitializationParameters;
        if (InitializationParameters.getPlayerCount() < 5) {
            int DeletedPlantationIndex = (int) (Plantations.size() * Math.random());
            InitializationParameters.setDeletedPlantation(Plantations.get(DeletedPlantationIndex));
            Plantations.remove(DeletedPlantationIndex);
        }
    }

    private Gameboard(DifficultyLevel Level, boolean PalmTree) {
        Plantations = new ArrayList<>();
        for (PlantationType t : PlantationType.values()) {
            for (int i = 0; i < 3; i++) {
                Plantations.add(new Plantation(t, (short) 1));
                Plantations.add(new Plantation(t, (short) 2));
                Plantations.add(new Plantation(t, (short) 2));
            }
        }
        initMap(PalmTree);
        defineSpring(Level);
    }

    private void defineSpring(DifficultyLevel Level) {
        int[] Choices;
        switch (Level) {
            case Easy:
                Choices = new int[]{6, 7, 8, 11, 12, 13};
                break;
            case Medium:
                Choices = new int[]{1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 19};
                break;
            case Hard:
                Choices = new int[]{0, 1, 2, 3, 5, 9, 10, 14, 16, 17, 18, 19};
                break;
            case Impossible:
                Choices = new int[]{0, 4, 15, 19};
                break;
            default:
                throw new AssertionError();
        }
        Spring = Choices[(int) (Math.random() * Choices.length)];
        Nodes[Spring].defineAsSpring();
    }

    private void initMap(boolean IncludePalmTree) {
        //initialize the map

        //create fields
        int RemainingPalmTree = IncludePalmTree ? 3 : 0;
        List<Field> Fields = new ArrayList<>();
        for (int i = 0; i < (IncludePalmTree ? 45 : 48); i++) {
            if (RemainingPalmTree > 0 && Math.random() <= 0.075) {
                Fields.add(new Field(true));
                RemainingPalmTree--;
            }
            Fields.add(new Field(false));
        }
        for (; RemainingPalmTree > 0; RemainingPalmTree--) {
            Fields.add(new Field(true));
        }

        //Create lots with the previous fields
        List<Lot> Lots = new ArrayList<>();
        for (int i = 0; i < 12; i++) {
            Lots.add(new Lot(Fields.remove((int) (Fields.size() * Math.random())),
                    Fields.remove((int) (Fields.size() * Math.random())),
                    Fields.remove((int) (Fields.size() * Math.random())),
                    Fields.remove((int) (Fields.size() * Math.random()))));
        }

        //Finish the gameboard initialization (arrange lots and canals)
        Nodes = new Node[20];
        //0
        Nodes[0] = new Node(
                null,
                new Canal(),
                new Canal(),
                null,
                null,
                Lots.remove(0),
                null,
                null);
        //1
        Nodes[1] = new Node(
                null,
                new Canal(),
                new Canal(),
                Nodes[0].getCanal(CardinalPoint.EAST),
                null,
                Lots.remove(0),
                Nodes[0].getLot(CardinalPoint.SOUTH_EAST),
                null);
        //2
        Nodes[2] = new Node(
                null,
                new Canal(),
                new Canal(),
                Nodes[1].getCanal(CardinalPoint.EAST),
                null,
                Lots.remove(0),
                Nodes[1].getLot(CardinalPoint.SOUTH_EAST),
                null);
        //3
        Nodes[3] = new Node(
                null,
                new Canal(),
                new Canal(),
                Nodes[2].getCanal(CardinalPoint.EAST),
                null,
                Lots.remove(0),
                Nodes[2].getLot(CardinalPoint.SOUTH_EAST),
                null);
        //4
        Nodes[4] = new Node(
                null,
                null,
                new Canal(),
                Nodes[3].getCanal(CardinalPoint.EAST),
                null,
                null,
                Nodes[3].getLot(CardinalPoint.SOUTH_EAST),
                null);
        //5
        Nodes[5] = new Node(
                Nodes[0].getCanal(CardinalPoint.EAST),
                new Canal(),
                new Canal(),
                null,
                Nodes[0].getLot(CardinalPoint.SOUTH_EAST),
                Lots.remove(0),
                null,
                null);
        //6
        Nodes[6] = new Node(
                Nodes[1].getCanal(CardinalPoint.SOUTH),
                new Canal(),
                new Canal(),
                Nodes[5].getCanal(CardinalPoint.EAST),
                Nodes[1].getLot(CardinalPoint.SOUTH_EAST),
                Lots.remove(0),
                Nodes[5].getLot(CardinalPoint.SOUTH_EAST),
                Nodes[1].getLot(CardinalPoint.SOUTH_WEST));
        //7
        Nodes[7] = new Node(
                Nodes[2].getCanal(CardinalPoint.SOUTH),
                new Canal(),
                new Canal(),
                Nodes[6].getCanal(CardinalPoint.EAST),
                Nodes[2].getLot(CardinalPoint.SOUTH_EAST),
                Lots.remove(0),
                Nodes[6].getLot(CardinalPoint.SOUTH_EAST),
                Nodes[2].getLot(CardinalPoint.SOUTH_WEST));
        //8
        Nodes[8] = new Node(
                Nodes[3].getCanal(CardinalPoint.SOUTH),
                new Canal(),
                new Canal(),
                Nodes[7].getCanal(CardinalPoint.EAST),
                Nodes[3].getLot(CardinalPoint.SOUTH_EAST),
                Lots.remove(0),
                Nodes[7].getLot(CardinalPoint.SOUTH_EAST),
                Nodes[3].getLot(CardinalPoint.SOUTH_WEST));
        //9
        Nodes[9] = new Node(
                Nodes[4].getCanal(CardinalPoint.SOUTH),
                null,
                new Canal(),
                Nodes[8].getCanal(CardinalPoint.EAST),
                null,
                null,
                Nodes[8].getLot(CardinalPoint.SOUTH_EAST),
                Nodes[4].getLot(CardinalPoint.SOUTH_WEST));
        //10
        Nodes[10] = new Node(
                Nodes[5].getCanal(CardinalPoint.SOUTH),
                new Canal(),
                new Canal(),
                null,
                Nodes[5].getLot(CardinalPoint.SOUTH_EAST),
                Lots.remove(0),
                null,
                null);
        //11
        Nodes[11] = new Node(
                Nodes[6].getCanal(CardinalPoint.SOUTH),
                new Canal(),
                new Canal(),
                Nodes[10].getCanal(CardinalPoint.EAST),
                Nodes[6].getLot(CardinalPoint.SOUTH_EAST),
                Lots.remove(0),
                Nodes[10].getLot(CardinalPoint.SOUTH_EAST),
                Nodes[6].getLot(CardinalPoint.SOUTH_WEST));
        //12
        Nodes[12] = new Node(
                Nodes[7].getCanal(CardinalPoint.SOUTH),
                new Canal(),
                new Canal(),
                Nodes[11].getCanal(CardinalPoint.EAST),
                Nodes[7].getLot(CardinalPoint.SOUTH_EAST),
                Lots.remove(0),
                Nodes[11].getLot(CardinalPoint.SOUTH_EAST),
                Nodes[7].getLot(CardinalPoint.SOUTH_WEST));
        //13
        Nodes[13] = new Node(
                Nodes[8].getCanal(CardinalPoint.SOUTH),
                new Canal(),
                new Canal(),
                Nodes[12].getCanal(CardinalPoint.EAST),
                Nodes[8].getLot(CardinalPoint.SOUTH_EAST),
                Lots.remove(0),
                Nodes[12].getLot(CardinalPoint.SOUTH_EAST),
                Nodes[8].getLot(CardinalPoint.SOUTH_WEST));
        //14
        Nodes[14] = new Node(
                Nodes[9].getCanal(CardinalPoint.SOUTH),
                null,
                new Canal(),
                Nodes[13].getCanal(CardinalPoint.EAST),
                null,
                null,
                Nodes[13].getLot(CardinalPoint.SOUTH_EAST),
                Nodes[9].getLot(CardinalPoint.SOUTH_WEST));
        //15
        Nodes[15] = new Node(
                Nodes[10].getCanal(CardinalPoint.SOUTH),
                new Canal(),
                null,
                null,
                Nodes[10].getLot(CardinalPoint.SOUTH_EAST),
                null,
                null,
                null);
        //16
        Nodes[16] = new Node(
                Nodes[11].getCanal(CardinalPoint.SOUTH),
                new Canal(),
                null,
                Nodes[15].getCanal(CardinalPoint.EAST),
                Nodes[11].getLot(CardinalPoint.SOUTH_EAST),
                null,
                null,
                Nodes[11].getLot(CardinalPoint.SOUTH_WEST));
        //17
        Nodes[17] = new Node(
                Nodes[12].getCanal(CardinalPoint.SOUTH),
                new Canal(),
                null,
                Nodes[16].getCanal(CardinalPoint.EAST),
                Nodes[12].getLot(CardinalPoint.SOUTH_EAST),
                null,
                null,
                Nodes[12].getLot(CardinalPoint.SOUTH_WEST));
        //18
        Nodes[18] = new Node(
                Nodes[13].getCanal(CardinalPoint.SOUTH),
                new Canal(),
                null,
                Nodes[17].getCanal(CardinalPoint.EAST),
                Nodes[13].getLot(CardinalPoint.SOUTH_EAST),
                null,
                null,
                Nodes[13].getLot(CardinalPoint.SOUTH_WEST));
        //19
        Nodes[19] = new Node(
                Nodes[14].getCanal(CardinalPoint.SOUTH),
                null,
                null,
                Nodes[18].getCanal(CardinalPoint.EAST),
                null,
                null,
                null,
                Nodes[14].getLot(CardinalPoint.SOUTH_WEST));
    }

    public Plantation[] drawPlantationLot() {
        Plantation[] Lot = new Plantation[InitializationParameters.getPlantationLotCount()];
        for (int i = 0; i < Lot.length; i++) {
            int PlantationIndex = (int) (Plantations.size() * Math.random());
            Lot[i] = Plantations.get(PlantationIndex);
            Plantations.remove(PlantationIndex);
        }
        return Lot;
    }

    public Node[] getNodes() {
        return Nodes;
    }

    /**
     * Return the index of the sprint in the node list
     *
     * @return
     */
    public int getSpring() {
        return Spring;
    }
}
